﻿/*
文件关联相关头文件
代码编写：Ansifa
2010/10/23
*/



!ifndef Project ;如果没有定义Project名则给一个
!define Project AssocTool
!endif

;文件打开字样，可以修改为你喜欢的
!ifndef OPEN
!define OPEN "用 ${Project} 打开 (&O)"
!endif

!include "logiclib.nsh"

/*********关联文件********
用法：
${Assoc} 扩展名 别名 文件类型描述 打开程序路径 图标路径
实例:
${Assoc} txt "txtfiles" "文本文档" "$WINDIR\notepad.exe" "%SystemRoot%\system32\imageres.dll,-102"

注意：所有参数为必须参数，不能缺少，空值可以使用空字符串代替如
${Assoc} txt "txtfiles" "文本文档" "$WINDIR\notepad.exe" ""
*/


!macro Assoc EXT TYPE DESC OPENEXE ICO
Push $1
Push $2
Push $3
/*
nsSkinEngine::log "EXT = ${ext}"
nsSkinEngine::log "TYPE = ${type}"
nsSkinEngine::log "DESC = ${desc}"
nsSkinEngine::log "OPENEXE = ${openexe}"
nsSkinEngine::log "ICO = ${ico}"
*/
;回显UnAssoc代码，以便写取消关联程序
!ifdef EchoUnSources
	DetailPrint '${UnAssoc} ${ext}'
!endif



;是否生成测试样本
!ifdef WriteTest
	CreateDirectory "$EXEDIR\文件关联测试样本"
	FileOpen $0 "$EXEDIR\文件关联测试样本\${desc}.${ext}" w
	FileWrite $0 ""
	FileClose $0
!endif

;显示关联字符串
!ifdef Echo
	ReadRegStr $1 HKCR ".${ext}" ""
	${if} $1 == ""
		DetailPrint '正在关联 *.${ext} 类型文件为 "${desc}"...'
	${Else}
		DetailPrint '更改 *.${ext} 类型文件关联为 "${desc}"...'
	${EndIf}
!endif


;识别当前基本关联前缀是否本程序,不是的话,备份当前关联.是空的话写"_Blank_"
ReadRegStr $1 HKCR ".${ext}" ""
;nsSkinEngine::log ".${ext}"
StrLen $3 "${Project}"
StrCpy $2 $1 $3
StrCmp $2 "${Project}" +4
WriteRegStr HKCR "Back.${Project}\.${ext}" "" "$1"
StrCmp $1 "" +1 +2
WriteRegStr HKCR "Back.${Project}\.${ext}" "" "_Blank_"

!ifdef StrongAssoc  ;强力关联
	;识别用户级关联
	ReadRegStr $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Application"
	;nsSkinEngine::log "Application = $1"
	StrCpy $2 $1; $3
	StrCmp $2 "${openexe}" +4
	WriteRegStr HKCR "Back.${Project}\.${ext}" "Application" "$1"
	StrCmp $1 "" +1 +2
	WriteRegStr HKCR "Back.${Project}\.${ext}" "Application" "_Blank_"

	ReadRegStr $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}\UserChoice" "Progid"
	;nsSkinEngine::log "Progid_UserChoice = $1"
	StrCpy $2 $1 $3
	StrCmp $2 "${Project}" +4
	WriteRegStr HKCR "Back.${Project}\.${ext}" "Progid_UserChoice" "$1"
	StrCmp $1 "" +1 +2
	WriteRegStr HKCR "Back.${Project}\.${ext}" "Progid_UserChoice" "_Blank_"

	ReadRegStr $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Progid"
	;nsSkinEngine::log "Progid = $1"
	StrCpy $2 $1 $3
	StrCmp $2 "${Project}" +4
	WriteRegStr HKCR "Back.${Project}\.${ext}" "Progid" "$1"
	StrCmp $1 "" +1 +2
	WriteRegStr HKCR "Back.${Project}\.${ext}" "Progid" "_Blank_"
!endif

;基本关联
WriteRegStr HKCR ".${ext}" "" "${Project}.${type}"
WriteRegStr HKCR "${Project}.${type}" "" "${desc}"
WriteRegStr HKCR "${Project}.${type}\shell" "" "open"
WriteRegStr HKCR "${Project}.${type}\shell\open" "" "${OPEN}"
WriteRegStr HKCR "${Project}.${type}\shell\open\command" "" '"${openexe}" %1'

!ifdef StrongAssoc  ;强力关联
;用户级别关联(增强文件类型和主程序黏性)
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Application" '${openexe}'
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}\UserChoice" "Progid" '${Project}.${type}'
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Progid" '${Project}.${type}'
!endif

;文件类型默认图标
${if} "${ico}" == ""   ;如果不指定图标则使用默认图标
	WriteRegStr HKCR "${Project}.${type}\DefaultIcon" "" "${openexe}"
${Else}
	WriteRegStr HKCR "${Project}.${type}\DefaultIcon" "" "${ico}"
${EndIf}

;文件类型默认图标之二:如果$EXEDIR\Icon\文件夹下面有${ext}.ico就使用${ext}.ico.
IfFileExists "$EXEDIR\Icon\${ext}.ico" +1 +2
WriteRegStr HKCR "${Project}.${type}\DefaultIcon" "" "$EXEDIR\Icon\${ext}.ico"

;标记有关联文件(只要非空即可)
WriteRegStr HKCR "Back.${Project}" "" "${Project} Backup"


Pop $3
Pop $2
Pop $1
!macroend
!define Assoc "!insertmacro Assoc"


/*********删除文件关联*********
用法：
${UnAssoc} 扩展名
实例:
${UnAssoc} txt
*/

!macro UnAssoc EXT
Push $1
Push $2
Push $3
Push $4
${if} "${ext}" != ""   ;所有操作必须基于析出的扩展名不为空，为空的话就跳过所有操作

	!ifdef StrongAssoc  ;强力关联
		;恢复用户级关联备份
		ReadRegStr $1 HKCR "Back.${Project}\.${ext}" "Application"
		;nsSkinEngine::log "UnAssoc Application = $1"
		StrCmp $1 "" +3
		WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Application" "$1"
		StrCmp $1 "_Blank_" +1 +2
		DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Application"
		
		ReadRegStr $1 HKCR "Back.${Project}\.${ext}" "Progid_UserChoice"
		;nsSkinEngine::log "UnAssoc Progid_UserChoice = $1"
		StrCmp $1 "" +3
		WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}\UserChoice" "Progid" "$1"
		StrCmp $1 "_Blank_" +1 +2
		DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}\UserChoice" "Progid"
		
		ReadRegStr $1 HKCR "Back.${Project}\.${ext}" "Progid"
		;nsSkinEngine::log "UnAssoc Progid = $1"
		StrCmp $1 "" +3
		WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Progid" "$1"
		StrCmp $1 "_Blank_" +1 +2
		DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" "Progid"
	!endif
	
	;恢复基本关联备份
	ReadRegStr $1 HKCR "Back.${Project}\.${ext}" "" 	;读备份
	ReadRegStr $2 HKCR ".${ext}" "" 					;读现在的
	;nsSkinEngine::log "UnAssoc Back.${Project}\.${ext} = $1"
	;nsSkinEngine::log "UnAssoc .${ext}" = $2"
	StrLen $3 ${Project}                            ;截取现在关联类型的前缀，识别是否已经关联
	StrCpy $4 $2 $3

	${if} "$4" == "${Project}"		;现在是不是关联了
		${if} "$1" == "_Blank_"  ;如果备份有"_Blank_",证明已经关联,但没有旧类型.
			DeleteRegValue HKCR ".${ext}" ""
			!ifdef UnEcho
				DetailPrint '正在恢复 *.${ext} 类型文件为无关联...'
			!endif
		${ElseIf} "$1" != ""
			ReadRegStr $1 HKCR "Back.${Project}\.${ext}" "" 	;读备份
			WriteRegStr HKCR ".${ext}" "" "$1"         ;恢复备份
			!ifdef UnEcho
				DetailPrint '正在取消 *.${ext} 类型文件的关联...'
			!endif
		${EndIf}
		StrCmp "${Project}.${ext}" "" +2
	${Else}
		!ifdef UnEcho
			DetailPrint '程序没有关联*.${ext},跳过取消关联操作...'
		!endif
		StrCmp "${Project}.${ext}" "" +2
	${EndIf}
	DeleteRegKey HKCR "Back.${Project}\.${ext}"   ;恢复完成,删除备份
	DeleteRegKey HKCR "${Project}.${ext}"	;删除基本关联

	;清理完全空的键值
	ReadRegStr $1 HKCR ".${ext}" ""
	StrCmp $1 "" +1 +2
	DeleteRegKey /ifempty HKCR ".${ext}"

	ReadRegStr $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}" ""
	StrCmp $1 "" +1 +2
	DeleteRegKey /ifempty HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.${ext}"

${EndIf}
Pop $4
Pop $3
Pop $2
Pop $1
!macroend
!define UnAssoc "!insertmacro UnAssoc"


/*********检测区段关联********
用法：
${CheckSection} "要检查的组件ID" "扩展名"
实例:
${UnAssoc} txt txt

备注："要检查的组件ID"就是下面语句
Section ".testa" "Sec_testa"
中的Sec_testa
*/
!macro CheckSection SECTION_NAME EXT
Push $0
Push $1
ReadRegStr $1 HKCR "Back.${Project}" ""     ;先看看有没执行过程序总关联
${if} $1 != ""
	ReadRegStr $0 HKCR ".${ext}" ""
	StrLen $1 "${Project}"
	StrCpy $0 $0 $1    ;是在.${EXT}截取${Project}前缀

	${if} "$0" == "${Project}"		;看现在是不是关联了
		SectionGetInstTypes "${${SECTION_NAME}}" $1
		IntOp $0 1 << ${Count_Of_InstType}      ;将InstType的"当前关联"位置1
		IntOp $1 $1 | $0
		SectionSetInstTypes "${${SECTION_NAME}}" $1
	${Else}
		SectionGetInstTypes "${${SECTION_NAME}}" $1
		IntOp $0 1 << ${Count_Of_InstType}      ;将InstType的"当前关联"位置0
		IntOp $0 $0 - 1
		IntOp $1 $1 & $0
		SectionSetInstTypes "${${SECTION_NAME}}" $1
	${EndIf}
${EndIf}
Pop $1
Pop $0
!macroend
!define CheckSection "!insertmacro CheckSection"

/*********头文件末尾*********/
